package io.zhengsh.nio.selector;

import org.junit.Test;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.Iterator;
import java.util.Scanner;
import java.util.Set;
import java.util.concurrent.TimeUnit;

public class ClientDemo {

    public static void main(String[] args) throws IOException {
        //1. 获取通道，绑定主机和端口号
        SocketChannel socketChannel = SocketChannel.open(new InetSocketAddress(20000));

        //2. 切换到非阻塞模式
        socketChannel.configureBlocking(false);

        //3. 创建 buffer
        ByteBuffer buffer = ByteBuffer.allocate(1024);

        Scanner scanner = new Scanner(System.in);
        while (scanner.hasNext()) {
            String str = scanner.next();
            //4. 写入 buffer 数据
            String s = new Date() + " ===> " + str;
            byte[] bytes = s.getBytes(StandardCharsets.UTF_8);
            buffer.put(bytes);

            //5. 模式切换
            buffer.flip();

            //6. 写入通道
            socketChannel.write(buffer);

            //7. 关闭
            buffer.clear();
        }

    }

    @Test
    public void server() throws IOException {
        //1. 获取服务端通道
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();

        //2. 切换非阻塞模式
        serverSocketChannel.configureBlocking(false);

        //3. 创建 buffer
        ByteBuffer readBuffer = ByteBuffer.allocate(1024);
        ByteBuffer writeBuffer = ByteBuffer.allocate(1024);
        writeBuffer.put("收到了。。。。".getBytes(StandardCharsets.UTF_8));

        //4. 绑定端口号
        serverSocketChannel.bind(new InetSocketAddress(20000));

        //5. 获取 selector 选择器
        Selector selector = Selector.open();

        //6. 通道注册到选择器，进行监听
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

        //7. 选择器进行轮训，进行后续操作
        while (selector.select() > 0) {
            Set<SelectionKey> selectionKeys = selector.selectedKeys();
            Iterator<SelectionKey> selectionKeyIterator = selectionKeys.iterator();
            // 循环
            while (selectionKeyIterator.hasNext()) {
                // 获取就绪状态
                SelectionKey k = selectionKeyIterator.next();

                // 操作判断
                if (k.isAcceptable()) {
                    // 获取连接
                    SocketChannel accept = serverSocketChannel.accept();

                    // 切换非阻塞模式
                    accept.configureBlocking(false);

                    // 注册
                    accept.register(selector, SelectionKey.OP_READ);
                } else if (k.isReadable()) {
                    SocketChannel socketChannel = (SocketChannel) k.channel();
                    readBuffer.clear();

                    int length = 0;
                    while ((length = socketChannel.read(readBuffer)) > 0) {
                        readBuffer.flip();
                        System.out.println("received:" + new String(readBuffer.array(), 0, length));
                        readBuffer.clear();
                    }
                    k.interestOps(SelectionKey.OP_WRITE);
                } else if (k.isWritable()) {
                    writeBuffer.rewind();

                    SocketChannel socketChannel = (SocketChannel) k.channel();
                    socketChannel.write(writeBuffer);
                    k.interestOps(SelectionKey.OP_READ);
                }
            }
            selectionKeyIterator.remove();
        }
    }

    @Test
    public void client() throws IOException, InterruptedException {

        //1. 获取通道，绑定主机和端口号
        SocketChannel socketChannel = SocketChannel.open(new InetSocketAddress(20000));

        //2. 切换到非阻塞模式
        socketChannel.configureBlocking(false);

        //3. 创建 buffer
        ByteBuffer buffer = ByteBuffer.allocate(1024);

        //4. 写入 buffer 数据
        buffer.put(new Date().toString().getBytes(StandardCharsets.UTF_8));

        //5. 模式切换
        buffer.flip();

        //6. 写入通道
        socketChannel.write(buffer);

        //7. 关闭
        buffer.clear();
        //socketChannel.close();

        TimeUnit.SECONDS.sleep(500);
    }
}
